<?php
/*
 *	Created on 2008-04-12 / 15:38:13
 *	Filename: bot.php
 *	User: tomusdrw (tomusdrw.blacksoft.pl)
 *	@author: Blacksoft.eu (c) 2008, 2009
 *	@package: tempaq2
 *	
 */

define ('OnJoin', 1);
define ('OnLeave', 2);
define ('OnMsg', 4);
define ('OnPriv', 8);
define ('OnChannel', 16);
define ('OnNick', 32);
define ('OnTopic', 64);
define ('OnAll', 128); //nie wiem co to lepiej nie uzywac:P nie no noł komments

class bot_base {
	public static $debug=BOT_DEBUG;
	public static function set_debug($dbg=null) {
		if ($dbg == null) return self::$debug;
		if (is_int($dbg)) { 
			self::$debug = $dbg;
			return $dbg;
		}
		return false;
	}
	/**
	 * Funkcja do debugowania (zapisuje log itp itd)
	 *
	 * @param string $msg
	 * @param int $lvl
	 */
	public function debug($msg, $type=DBG_ERROR, $lvl=1) {
		if (isset($this->exec_module)) {
			$module = $this->exec_module;
			$msg = '(MODULE: '.$module.') '.$msg;
		}
		debug($msg, $type, $lvl);
	}
	public $autojoin=BOT_AUTOJOIN;
	public $runningsince=0;
	protected $safe = false;
	/**
	 * Tablica z funkcjami(nazwa=>tresc)
	 *
	 * @var array
	 */
	protected $func = array();
	/**
	 * Czas działania
	 *
	 * @var int
	 */
	protected $time = 0;
	/**
	 * Przechowuje referencje na klase SMARTIRC
	 *
	 * @var SMARTIRC
	 */
	protected $irc;
	/**
	 * Obiekt typu lang
	 *
	 * @var LANG
	 */
	public $lang;
	/**
	 * Tablica operatorow(adminow)
	 *
	 * @var array
	 */
	protected $ops = array();
	/**
	 * Tablica funkcji ktore wykonuja sie co okreslony czas (min 10ms).
	 * W postaci [co_ile]=>nazwafunkcji
	 *
	 * @var array
	 */
	protected $ontimer = array();
	protected $onnick = array();
	/**
	 * Tablica funkcji ktore wykonuja sie kiedy ktos wchodzi na kanał
	 *
	 * @var array
	 */
	protected $onjoin = array();
	/**
	 * Tablica funkcji ktore wykonuja sie kiedy ktos opuszca kanal
	 *
	 * @var array
	 */
	protected $onleave = array();
	/**
	 * Funkcje wykonujace sie przy zmianie tematu
	 *
	 * @var array
	 */
	protected $ontopic = array();
	/**
	 * Funkcje przy wiadomosci prywatnej
	 *
	 * @var array
	 */
	protected $onquery = array();
	/**
	 * Dowolna wiadomosc na kanale
	 *
	 * @var array
	 */
	protected $onchannelmsg = array();
	/**
	 * Gdy ktos wychodzi
	 *
	 * @var array
	 */
	protected $onall = array();
	protected $justunloaded;
	/**
	 * Tablica w ktorej sa nazwy tablic z funkcjami na dana okazje
	 *
	 * @var array
	 */
	protected $tablice = array('onjoin', 'onall', 'onnick', 'onchannelmsg', 'onquery', 'ontopic', 'onleave');
	/**
	 * Tablica z pomoca
	 *
	 * @var array
	 */
	protected $help = array();
	/**
	 * Przechowuje dane dotyczące danego modułu
	 *
	 * @var array
	 */
	protected $modulesinfo = array();
	/**
	 * Tymczasowo przechowuje obiekt SMARTIRC_data na czas wykonwywania funkcji
	 *
	 * @var SMARTIRC_data
	 */
	protected $data_temp=null;
	/**
	 * Temat ktory ma być zawsze ustawiany
	 *
	 * @var string
	 */
	public $topic_lock=null;
	protected $exec_module;
	protected $module_memory = array();
}

class bot_functions extends bot_base {
	public function setDebug($lvl = null) {
		if (isset($lvl)) {
			bot_base::set_debug((int)$lvl);
			switch ($lvl) {
				case 0:
					$ircdbg = SMARTIRC_DEBUG_NONE;
				case 2:
					$ircdbg = SMARTIRC_DEBUG_CONNECTION | SMARTIRC_DEBUG_NOTICE;
					break;
				case 3:
					$ircdbg = SMARTIRC_DEBUG_IRCMESSAGES | SMARTIRC_DEBUG_CONNECTION | SMARTIRC_DEBUG_NOTICE;
					break;
				case 4:
					$ircdbg = SMARTIRC_DEBUG_MODULES | SMARTIRC_DEBUG_IRCMESSAGES | SMARTIRC_DEBUG_CONNECTION | SMARTIRC_DEBUG_NOTICE;
					break;
				case 5:
					$ircdbg = SMARTIRC_DEBUG_ALL;
					break;
				default:
					$ircdbg = SMARTIRC_DEBUG_NOTICE;
			}
			$this->irc->setDebug($ircdbg);
			$this->debug('Debug lvl changed: '.bot_base::set_debug().' by '.$this->data_temp->nick, DBG_WARN);
		}
		return bot_base::set_debug();
	}
	/**
	 * Converts coding or removes polish letters like ąę
	 * Avaible: utf-8 iso-8859-2 windows-1250 bez-ogonkow
	 *
	 * @param string $kodowanie
	 * @param string $string
	 * @return string
	 */
	public function my_iconv($kodowanie, $string) {
		$x2utf = array(
			"\xc3\xb3" => "\xc3\xb3", "\xc5\xba" => "\xc5\xbc", "\xc5\xbc" => "\xc5\xba",
			"\xc5\xb9" => "\xc5\xbb", "\xc5\xbb" => "\xc5\xb9",
			"\xb1" => "\xc4\x85", "\xa1" => "\xc4\x84", "\xe6" => "\xc4\x87", "\xc6" => "\xc4\x86",
			"\xea" => "\xc4\x99", "\xca" => "\xc4\x98", "\xb3" => "\xc5\x82", "\xa3" => "\xc5\x81",
			"\xf3" => "\xc3\xb3", "\xd3" => "\xc3\x93", "\xb6" => "\xc5\x9b", "\xa6" => "\xc5\x9a",
			"\xbc" => "\xc5\xbc", "\xac" => "\xc5\xbb", "\xbf" => "\xc5\xba", "\xaf" => "\xc5\xb9",
			"\xf1" => "\xc5\x84", "\xd1" => "\xc5\x83",
			"\xb9" => "\xc4\x85", "\xa5" => "\xc4\x84", "\xe6" => "\xc4\x87", "\xc6" => "\xc4\x86",
			"\xea" => "\xc4\x99", "\xca" => "\xc4\x98", "\xb3" => "\xc5\x82", "\xa3" => "\xc5\x81",
			"\xf3" => "\xc3\xb3", "\xd3" => "\xc3\x93", "\x9c" => "\xc5\x9b", "\x8c" => "\xc5\x9a",
			"\x9f" => "\xc5\xbc", "\x8f" => "\xc5\xbb", "\xbf" => "\xc5\xba", "\xaf" => "\xc5\xb9",
			"\xf1" => "\xc5\x84", "\xd1" => "\xc5\x83" );
		$utfflip = array("\xc5\xbc" => "\xc5\xba", "\xc5\xbb" => "\xc5\xb9",
			"\xc5\xba" => "\xc5\xbc", "\xc5\xb9" => "\xc5\xbb");
		$win2utf = array(
			"\xb9" => "\xc4\x85", "\xa5" => "\xc4\x84", "\xe6" => "\xc4\x87", "\xc6" => "\xc4\x86",
			"\xea" => "\xc4\x99", "\xca" => "\xc4\x98", "\xb3" => "\xc5\x82", "\xa3" => "\xc5\x81",
			"\xf3" => "\xc3\xb3", "\xd3" => "\xc3\x93", "\x9c" => "\xc5\x9b", "\x8c" => "\xc5\x9a",
			"\x9f" => "\xc5\xbc", "\x8f" => "\xc5\xbb", "\xbf" => "\xc5\xba", "\xaf" => "\xc5\xb9",
			"\xf1" => "\xc5\x84", "\xd1" => "\xc5\x83" );
		$iso2utf = array(
			"\xb1" => "\xc4\x85", "\xa1" => "\xc4\x84", "\xe6" => "\xc4\x87", "\xc6" => "\xc4\x86",
			"\xea" => "\xc4\x99", "\xca" => "\xc4\x98", "\xb3" => "\xc5\x82", "\xa3" => "\xc5\x81",
			"\xf3" => "\xc3\xb3", "\xd3" => "\xc3\x93", "\xb6" => "\xc5\x9b", "\xa6" => "\xc5\x9a",
			"\xbc" => "\xc5\xbc", "\xac" => "\xc5\xbb", "\xbf" => "\xc5\xba", "\xaf" => "\xc5\xb9",
			"\xf1" => "\xc5\x84", "\xd1" => "\xc5\x83" );
		$u2plk = array(
			"\xc4\x85" => "a", "\xc4\x84" => "A", "\xc4\x87" => "c", "\xc4\x86" => "C",
			"\xc4\x99" => "e", "\xc4\x98" => "E", "\xc5\x82" => "l", "\xc5\x81" => "L",
			"\xc3\xb3" => "o", "\xc3\x93" => "O", "\xc5\x9b" => "s", "\xc5\x9a" => "S",
			"\xc5\xbc" => "z", "\xc5\xbb" => "Z", "\xc5\xba" => "z", "\xc5\xb9" => "Z",
			"\xc5\x84" => "n", "\xc5\x83" => "N" );
		$string = strtr($string, $x2utf);
		switch (strtolower($kodowanie))	{
			case 'utf-8':			return strtr($string, $utfflip);
			case 'iso-8859-2':		return strtr($string, array_flip($iso2utf));
			case 'windows-1250':	return strtr($string, array_flip($win2utf));
			default:				return strtr($string, $u2plk);
		}
	}
	/**
	 * Removes some type characters from text
	 *
	 * @param string $tekst
	 * @param bool $cyfry
	 * @param bool $spacje
	 * @return string
	 */
	public function basicchars($tekst, $cyfry = false, $spacje = false) {
		$tekst = html_entity_decode(strtolower($this->my_iconv('bez-ogonkow', $tekst)));
		if ($cyfry) $temp = strtr($tekst, '1234567890-', '----------X');
		elseif ($spacje) $temp = strtr($tekst, 'qwertyuiopasdfghjklzxcvbnm1234567890 -', '-------------------------------------X');
		else $temp = strtr($tekst, 'qwertyuiopasdfghjklzxcvbnm1234567890-', '------------------------------------X');
		$i = 0;
		$output = '';
		while ($i < strlen($tekst))	{ if ($temp[$i] == '-') { $output .= $tekst[$i]; } $i++; }
		if ($spacje) return strtr(trim($output), ' ', '-');
		elseif ($cyfry)	{
			if ($output == '') return 0;
			else return $output;
		} else return $output;
	}
	// BEGINNING OF isUrl() function
	public function isUrl( $urladdr, $options="" ) {
	
	    // Force Options parameter to be lower case
	    // DISABLED PERMAMENTLY - OK to remove from code
	    //    $options = strtolower($options);
	
	    // Check Options Parameter
	    if (!ereg( '^([sHSEFuPaIpfqr][+?-])*$', $options ))
	    {
	        trigger_error("Options attribute malformed", E_USER_ERROR);
	    }
	
	    // Set Options Array, set defaults if options are not specified
	    // Scheme
	    if (strpos( $options, 's') === false) $aOptions['s'] = '?';
	    else $aOptions['s'] = substr( $options, strpos( $options, 's') + 1, 1);
	    // http://
	    if (strpos( $options, 'H') === false) $aOptions['H'] = '?';
	    else $aOptions['H'] = substr( $options, strpos( $options, 'H') + 1, 1);
	    // https:// (SSL)
	    if (strpos( $options, 'S') === false) $aOptions['S'] = '?';
	    else $aOptions['S'] = substr( $options, strpos( $options, 'S') + 1, 1);
	    // mailto: (email)
	    if (strpos( $options, 'E') === false) $aOptions['E'] = '-';
	    else $aOptions['E'] = substr( $options, strpos( $options, 'E') + 1, 1);
	    // ftp://
	    if (strpos( $options, 'F') === false) $aOptions['F'] = '-';
	    else $aOptions['F'] = substr( $options, strpos( $options, 'F') + 1, 1);
	    // User section
	    if (strpos( $options, 'u') === false) $aOptions['u'] = '?';
	    else $aOptions['u'] = substr( $options, strpos( $options, 'u') + 1, 1);
	    // Password in user section
	    if (strpos( $options, 'P') === false) $aOptions['P'] = '?';
	    else $aOptions['P'] = substr( $options, strpos( $options, 'P') + 1, 1);
	    // Address Section
	    if (strpos( $options, 'a') === false) $aOptions['a'] = '+';
	    else $aOptions['a'] = substr( $options, strpos( $options, 'a') + 1, 1);
	    // IP Address in address section
	    if (strpos( $options, 'I') === false) $aOptions['I'] = '?';
	    else $aOptions['I'] = substr( $options, strpos( $options, 'I') + 1, 1);
	    // Port number
	    if (strpos( $options, 'p') === false) $aOptions['p'] = '?';
	    else $aOptions['p'] = substr( $options, strpos( $options, 'p') + 1, 1);
	    // File Path
	    if (strpos( $options, 'f') === false) $aOptions['f'] = '?';
	    else $aOptions['f'] = substr( $options, strpos( $options, 'f') + 1, 1);
	    // Query Section
	    if (strpos( $options, 'q') === false) $aOptions['q'] = '?';
	    else $aOptions['q'] = substr( $options, strpos( $options, 'q') + 1, 1);
	    // Fragment (Anchor)
	    if (strpos( $options, 'r') === false) $aOptions['r'] = '?';
	    else $aOptions['r'] = substr( $options, strpos( $options, 'r') + 1, 1);
	
	
	    // Loop through options array, to search for and replace "-" to "{0}" and "+" to ""
	    foreach($aOptions as $key => $value)
	    {
	        if ($value == '-')
	        {
	            $aOptions[$key] = '{0}';
	        }
	        if ($value == '+')
	        {
	            $aOptions[$key] = '';
	        }
	    }
	    
	    // DEBUGGING - Unescape following line to display to screen current option values
	    // echo '<pre>'; print_r($aOptions); echo '</pre>';
	
	
	    // Preset Allowed Characters
	    $alphanum    = '[a-zA-Z0-9]';  // Alpha Numeric
	    $unreserved  = '[a-zA-Z0-9_.!~*' . '\'' . '()-]';
	    $escaped     = '(%[0-9a-fA-F]{2})'; // Escape sequence - In Hex - %6d would be a 'm'
	    $reserved    = '[;/?:@&=+$,]'; // Special characters in the URI
	    
	    // Beginning Regular Expression
	                       // Scheme - Allows for 'http://', 'https://', 'mailto:', or 'ftp://'
	    $scheme            = '(';
	    if     ($aOptions['H'] === '') { $scheme .= 'http://'; }
	    elseif ($aOptions['S'] === '') { $scheme .= 'https://'; }
	    elseif ($aOptions['E'] === '') { $scheme .= 'mailto:'; }
	    elseif ($aOptions['F'] === '') { $scheme .= 'ftp://'; }
	    else
	    {
	        if ($aOptions['H'] === '?') { $scheme .= '|(http://)'; }
	        if ($aOptions['S'] === '?') { $scheme .= '|(https://)'; }
	        if ($aOptions['E'] === '?') { $scheme .= '|(mailto:)'; }
	        if ($aOptions['F'] === '?') { $scheme .= '|(ftp://)'; }
	        $scheme = str_replace('(|', '(', $scheme); // fix first pipe
	    }
	    $scheme            .= ')' . $aOptions['s'];
	    // End setting scheme
	    
	                       // User Info - Allows for 'username@' or 'username:password@'. Note: contrary to rfc, I removed ':' from username section, allowing it only in password.
	                       //   /---------------- Username -----------------------\  /-------------------------------- Password ------------------------------\
	    $userinfo          = '((' . $unreserved . '|' . $escaped . '|[;&=+$,]' . ')+(:(' . $unreserved . '|' . $escaped . '|[;:&=+$,]' . ')+)' . $aOptions['P'] . '@)' . $aOptions['u'];
	    
	                       // IP ADDRESS - Allows 0.0.0.0 to 255.255.255.255
	    $ipaddress         = '((((2(([0-4][0-9])|(5[0-5])))|([01]?[0-9]?[0-9]))\.){3}((2(([0-4][0-9])|(5[0-5])))|([01]?[0-9]?[0-9])))';
	    
	                       // Tertiary Domain(s) - Optional - Multi - Although some sites may use other characters, the RFC says tertiary domains have the same naming restrictions as second level domains
	    $domain_tertiary   = '(' . $alphanum . '(([a-zA-Z0-9-]{0,62})' . $alphanum . ')?\.)*';
	
	                       // Second Level Domain - Required - First and last characters must be Alpha-numeric. Hyphens are allowed inside.
	    $domain_secondary  = '(' . $alphanum . '(([a-zA-Z0-9-]{0,62})' . $alphanum . ')?\.)';
	    
	    /* // This regex is disabled on purpose in favour of the more exact version below
	                       // Top Level Domain - First character must be Alpha. Last character must be AlphaNumeric. Hyphens are allowed inside.
	    $domain_toplevel   = '([a-zA-Z](([a-zA-Z0-9-]*)[a-zA-Z0-9])?)';
	    */
	    
	                       // Top Level Domain - Required - Domain List Current As Of December 2004. Use above escaped line to be forgiving of possible future TLD's
	    $domain_toplevel   = '(aero|biz|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|post|pro|travel|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|az|ax|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cs|cu|cv|cx|cy|cz|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|um|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw)';
	    
	
	                       // Address can be IP address or Domain
	    if ($aOptions['I'] === '{0}') {       // IP Address Not Allowed
	        $address       = '(' . $domain_tertiary . $domain_secondary . $domain_toplevel . ')';
	    } elseif ($aOptions['I'] === '') {  // IP Address Required
	        $address       = '(' . $ipaddress . ')';
	    } else {                            // IP Address Optional
	        $address       = '((' . $ipaddress . ')|(' . $domain_tertiary . $domain_secondary . $domain_toplevel . '))';
	    }
	    $address = $address . $aOptions['a'];
	    
	                       // Port Number - :80 or :8080 or :65534 Allows range of :0 to :65535
	                       //    (0-59999)         |(60000-64999)   |(65000-65499)    |(65500-65529)  |(65530-65535)
	    $port_number       = '(:(([0-5]?[0-9]{1,4})|(6[0-4][0-9]{3})|(65[0-4][0-9]{2})|(655[0-2][0-9])|(6553[0-5])))' . $aOptions['p'];
	    
	                       // Path - Can be as simple as '/' or have multiple folders and filenames
	    $path              = '(/((;)?(' . $unreserved . '|' . $escaped . '|' . '[:@&=+$,]' . ')+(/)?)*)' . $aOptions['f'];
	    
	                       // Query Section - Accepts ?var1=value1&var2=value2 or ?2393,1221 and much more
	    $querystring       = '(\?(' . $reserved . '|' . $unreserved . '|' . $escaped . ')*)' . $aOptions['q'];
	    
	                       // Fragment Section - Accepts anchors such as #top
	    $fragment          = '(#(' . $reserved . '|' . $unreserved . '|' . $escaped . ')*)' . $aOptions['r'];
	    
	    
	    // Building Regular Expression
	    $regexp = '^' . $scheme . $userinfo . $address . $port_number . $path . $querystring . $fragment . '$';
	    
	    // DEBUGGING - Uncomment Line Below To Display The Regular Expression Built
	    // echo '<pre>' . htmlentities(wordwrap($regexp,70,"\n",1)) . '</pre>';
	
	    // Running the regular expression
	    if (eregi( $regexp, $urladdr ))
	    {
	        return true; // The domain passed
	    }
	    else
	    {
	        return false; // The domain didn't pass the expression
	    }
	
	}
	/**
	 * Odczytuje czas zapisany w zmiennej time i zamienia na bardziej przystepna postac ktora da sie wyswietlic
	 *
	 * @return string
	 */
	public function mktime() {
		$time = time()-$this->runningsince;
		//$time = $time/1000;
		$ret = $time.'s';
		if ($time>(3600*24)) {
			$ret = floor($time/(3600*24)).'d '.floor(($time%(3600*24))/3600).'h '.floor(($time%3600)/60).'m '.(($time%3600)%60).'s';
		} else if ($time>3600) {
			$ret = floor($time/3600).'h '.floor(($time%3600)/60).'m '.(($time%3600)%60).'s';
		} else if ($time>60) {
			$ret = floor($time/60).'m '.($time%60).'s';
		} 
		return $this->lang->text('uptime', $ret);
	}
	/**
	 * Funkcja sprawdza poprawnosc skladniowa pliku z modulem
	 *
	 * @param string $path sciezka do pliku z modułem
	 * @return bool
	 */
	public function syntax_check($path) {
		$this->debug('Syntax check of file: '.$path, DBG_INFO, 3);
		exec(PHP_PATH.' -l '.$path, &$output);
		if (substr_count($output[0], 'No syntax errors detected')) {
			$this->debug('Syntax: File: '.$path.' [OK]', DBG_INFO, 2);
			return true;
		}
		$this->debug('Syntax: File: '.$path.' [ERROR]', DBG_WARN, 1);
		return false;
	}
	/**
	 * Funkcja parsuje plik modułu i zwraca tablice
	 *
	 * @param string $file sciezka do pliku z modułem
	 * @return array / int
	 */
	public function parse($file) {
		$file = file_get_contents($file);
		$dzialanie = substr($file,strpos($file,'/**')+3,strpos($file,'*/')-strpos($file,'/**')-4);
		$modreg_start = '//*module_register_start';
		$modreg_end = '//*module_register_end';
		$func_start = '//*function_start';
		$func_end = '//*function_end';
		$ret['module_register'] = trim(substr(
											 $file, 
											 ( (substr_count($file, $modreg_start))?
											   (strpos($file, $modreg_start)+strlen($modreg_start)):
											   strlen($file) ),
											 ( (substr_count($file, $modreg_end))?
											   (strpos($file, $modreg_end)-strpos($file, $modreg_start)-strlen($modreg_end."\n\r"))
											   : ( (substr_count($file, $func_start))?
											       (strpos($file, $func_start)-strpos($file, $modreg_start)-strlen($modreg_start))
											       : null) ) ) );
		$ret['func'] = substr(
							 $file,
							 strpos($file, $func_start)+strlen($func_start),
							 ( (substr_count($file, $func_end))?
							 	( strpos($file, $func_end)-strpos($file, $func_start)-strlen($func_end."\n\r") )
							 	: (strrpos($file, "\n")-strpos($file, $func_start)-1)));
		if (substr_count($ret['func'], '?>'))
			$ret['func'] = substr($ret['func'], 0, strrpos($ret['func'], '?>'));
		
		if (strlen($ret['func'])<2) return 0;
	//	debug("*****!!!This is IT '".nonl($ret['func']).'\' *************', DBG_ERROR);
		$dzialanie = explode('*', str_replace("\n\r","",$dzialanie));
		//pomijamy element 0 (pusty)
	//	$this->debug('TEST!: count('.count($dzialanie).')');
		$d = count($dzialanie);
		for ($i=1; $i<$d; $i++) {
			$co = explode(': ', $dzialanie[$i]);
			if (count($co)<1) return 0;
			$name = trim(strtolower($co[0]));
			$co[1] = trim($co[1]);
		//	$this->debug('TEST!: name:'.$name);
			switch ($name) {
				case 'when':
				case 'provides':
					$co[1] = explode(' ', $co[1]);
					break;					
			}
			$ret[$name]=$co[1];
			unset($co);
		}
		return $ret;
	}
	/**
	 * Rejestruje obiekt modułu
	 *
	 * @param string $name
	 * @param string $evalcode
	 */
	public function register_module($name, $evalcode) {
		$bot = &$this;
		$irc = &$this->irc;
		$this->modulesinfo[$name]['module'] = new module($name, $this);
		$module = &$this->modulesinfo[$name]['module'];
		$this->exec_module = $name;
		$lang = $this->lang;
		$lang->module($name);
		eval($evalcode);
		$lang->unmodule();
		unset($this->exec_module);
	}
	/**
	 * Dodaje funckje do wykonanywania przy okreslonych zdarzeniach
	 *
	 * @param string $name Nazwa funkcji
	 * @param mixed $when Kiedy ma sie wykonywac
	 * @param string $func Cialo funkcji
	 */
	public function add_function($name, $when, $func) {
		$this->func[$name] = $func;
		switch ($when) {
			case OnJoin:
				$this->onjoin[]=$name;
				$this->debug('onJoin: Registering function "'.$name.'"', DBG_INFO, 2);
				break;
			case OnLeave:
				$this->onleave[]=$name;
				$this->debug('onLeave: Registering function "'.$name.'"', DBG_INFO, 2);
				break;
			case OnMsg:
				$this->onchannelmsg[]=$name;
				$this->onquery[]=$name;
				$this->debug('onMsg: Registering function "'.$name.'"', DBG_INFO, 2);
				break;
			case OnPriv:
				$this->onquery[]=$name;
				$this->debug('onQuery: Registering function "'.$name.'"', DBG_INFO, 2);
				break;
			case OnChannel:
				$this->onchannelmsg[]=$name;
				$this->debug('onChannelMsg: Registering function "'.$name.'"', DBG_INFO, 2);
				break;
			case OnNick:
				$this->onnick[]=$name;
				$this->debug('onNick: Registering function "'.$name.'"', DBG_INFO, 2);
			case OnAll:
				$this->onall[]=$name;
				$this->debug('onAll: Registering function "'.$name.'"', DBG_INFO, 2);
				break;
			case OnTopic:
				$this->ontopic[]=$name;
				$this->debug('onTopic: Registering function "'.$name.'"', DBG_INFO, 2);
				break;
			default: 
				if (is_numeric($a=substr($when, strlen("Every")))) {
					$this->ontimer[$a]=$name;
					$this->debug('onTimer('.$a.'): Registering function "'.$name.'"', DBG_INFO, 2);
				} else if(substr_count($when, "Every")) {
					unset($this->func[$name]);
					$this->sendmessage($this->lang->text('add_error'));
					$this->debug('Registering function "'.$name.'" error', DBG_ERROR, 1);
				} else {
					$this->debug('Ignoring function ('.$name.') action: '.$when, DBG_WARN, 1);
				}
		}
	}
	/**
	 * Funkcja sprawdza czy osoba o podanym nicku jest administratorem bota
	 *
	 * @param string $who
	 * @return bool
	 */
	public function is_admin($who, &$data=null) {
		if ($data === null) $data = $this->data_temp;
		//$userdata = $this->irc->channel[$this->data_temp->channel]->users[strtolower($who)];
		$this->debug('Admin check: '.$who, DBG_INFO, 3);
		foreach ($this->ops as $v) {
			if ($v['name'] == $who) {
				if (isset($data) && $data->nick == $who) {
					$d = &$data;
					if (
						$d->ident == $v['ident'] && 
						($d->host == $v['host'] || $v['host'] == '-'))
							return true; 
				} else {
					foreach ($this->irc->channel as $c) {
						if (is_object($c)) {
							if (isset($c->users[strtolower($who)])) {
								$userdata = $c->users[strtolower($who)]; 
								if ($userdata->ident == $v['ident']) {
									if ($v['host']=='-'||($v['host']==$userdata->host)) {
										return true;
									}
								}
							}
						}
					}
					return 0;
				}
			}
		}
		return false;
	}
	/**
	 * Funkcja ładuje moduły z katalogu modules
	 *
	 * @param SMARTIRC_data $data
	 */
	public function load_modules(&$data, $listonly=0, $directory=null) {
		$bad = array('.','..','lang','other', '.svn');
		$direc = '';
		if ($directory === null)
			$directory = MODULES_DIR;
		else
			$direc = substr($directory, strlen(MODULES_DIR.DIRECTORY_SEPARATOR));
		$dir = scandir($directory);
		if (is_array($dir)) {
			$modules=array();
			foreach ($dir as $v) {
				$name = $v;
				if (is_dir($directory.DIRECTORY_SEPARATOR.$v) && !in_array($v, $bad)) {
					$x = $this->load_modules($data, $listonly, $directory.DIRECTORY_SEPARATOR.$v);
					//debug($direc.'/'.$v.': '.count($x)."\n");
					foreach ($x as $klucz=>$a) {
						$modules[$klucz]=$a;
					}
				} elseif (!in_array($v, $bad)) {
					$v = explode('.', $v);
					if (count($v)>1) {
						if ($v[count($v)-1] == 'php') {
							if (is_array($p = $this->parse(MODULES_DIR.$direc.DIRECTORY_SEPARATOR.$name))) {
								if ($listonly & !$this->is_loaded($p['name'])) {
									$modules[$p['name']] = array_merge(array('filename' => $direc.DIRECTORY_SEPARATOR.$v[0]), $p);
								}
								$module = null;
								if (isset($this->modulesinfo[$p['name']])) {
									if (isset($this->modulesinfo[$p['name']]['module']))
										$module = $this->modulesinfo[$p['name']]['module'];
									unset($this->modulesinfo[$p['name']]);
								}
								$this->modulesinfo[$p['name']] = array_merge(array('module' => $module, 'filename' => $direc.DIRECTORY_SEPARATOR.$v[0]), $p);
								//TODO: testowe!!!! Nie wiem czy to nie jest do czegos potrzebne w tej tablicy!
								$this->modulesinfo[$p['name']]['func']=null;
								if (!$listonly)
									$this->load_module($direc.DIRECTORY_SEPARATOR.$v[0], $data, 1, $direc);
							}
						}
					}
				}
			}
			return (count($modules))?$modules:(($listonly)?array():$this->modulesinfo);
		}
	}
	/**
	 * Funkcja resetuje obecne tablcie zaladowanych modułow i ładuje moduły z plików na nowo
	 *
	 * @param SMARTIRC_data $data
	 */
	public function force_reload(&$data=null) {
		$tablice = $this->tablice;
		foreach ($tablice as $v) {
			$this->$v=array();
		}
		$this->func = array();
		$this->debug('Reloading modules', DBG_INFO, 2);
		$this->load_modules($data);
	}
	/**
	 * Funkcja ładująca konkretny moduł
	 *
	 * @param string $name nazwa_modułu
	 * @param SMARTIRC_data $data 
	 * @param int $autoload czy jest to ladowanie wymuszone
	 * @return bool
	 */	
	public function load_module($name, &$data=null, $autoload=0) {
		if ($data===null && isset($this->data_temp)) $data = $this->data_temp;
		$module = MODULES_DIR.$name.'.php';
		$this->debug('Trying to load module '.$module, DBG_INFO, 3);
		if (file_exists($module)) {
			$parsed = $this->parse($module);
			if (is_array($parsed)) {
				if ($this->syntax_check($module)) {
					if (isset($parsed['name']) && $this->is_loaded($parsed['name'])) {
						$this->unload_module($parsed['name']);
					}
					$this->lang->load_module($parsed['name'], substr($name, strrpos($name, DIRECTORY_SEPARATOR)));
					if ((isset($parsed['autoload']) && $parsed['autoload']=="false" && $autoload==1) || ($autoload==1 && $this->safe)) return false;
//					$this->debug('TEST!: when:'.$parsed['when'].'; [0]'.$parsed['when'][0]);
					if (!empty($parsed['module_register'])) {
						$this->register_module($parsed['name'], $parsed['module_register']);
					}
					if (isset($parsed['when']) && is_array($parsed['when']))
						foreach ($parsed['when'] as $v) {
							$this->add_function($parsed['name'], (defined($v))?constant($v):$v, $parsed['func']);
						}
					
					if (isset($parsed['provides']) && count($parsed['provides'])>0 && $parsed['provides'][0]!=='NONE') {
						foreach ($parsed['provides'] as $v){
							if (!in_array($v, $this->help))
								$this->help[]=$v;
						}
					}
			/*		if (isset($parsed['description']) && $parsed['description']!=='NONE') {
						$this->modulesinfo[$parsed['name']]=$parsed['description'];
					}*/
					$this->debug('Module '.(isset($parsed['name'])?$parsed['name']:$module).' loaded', DBG_INFO, 2);
					return true;
				} else {
					$this->send($this->lang->text('module_wrong_syntax', $parsed['name']), $data);
				}
			} else {
				$this->send($this->lang->text('wrong_module', $name), $data);
			}
		} else {
			$this->send($this->lang->text('module_not_exists', $name), $data);
		}
		$this->debug('Module '.$module.' loading failed!', DBG_WARN, 2);
		return false;
	}
	/**
	 * Usuwa moduł z pamięci tempaka
	 *
	 * @param string $name nazwamodułu(lub pliku z modułem)
	 */
	public function unload_module($name) {
		$this->debug('Trying to unload module '.$name, DBG_INFO, 3);
		if (isset($this->func[$name])) {
			unset($this->func[$name]);
			//wywalamy jezyk
			if ($this->lang->unload_module($name)) 
					$this->debug('Module '.$name.': lang unloaded.', DBG_INFO, 1);
			//unset($this->modulesinfo[$name]);
			$nie_usuwac = array('filename', 'desc');
			foreach ($this->modulesinfo[$name] as $k=>$v) {
				if (!in_array($k, $nie_usuwac)) {
					unset($this->modulesinfo[$name][$k]);
				}
			}
			$tablice = $this->tablice;
			//$tablice[]='help';
			$tablice[]='ontimer';
			foreach ($tablice as $v) {
				if (in_array($name, $this->$v)) {
					$x = array_keys($this->$v, $name);
					$asd = &$this->$v;
					unset($asd[$x[0]], $x);
					$this->$v = array_values($asd);
					unset($asd);
				}
				
			}
			$this->justunloaded[]=$name;
			$this->debug('Module '.$name.' unloaded.', DBG_INFO, 2);
			return true;
		}
		return false;
	}
	/**
	 * Przeładowuje aktulanie załadowane moduły (nie patrzy na AUTOLOAD)
	 *
	 * @param SMARTIRC_data $data
	 */
	public function reload_active_modules(&$data) {
		foreach ($this->func as $k=>$v) {
			$this->load_module($this->modulesinfo[$k]['filename'], $data);
		}
	}
	/**
	 * Sprawdza czy moduł o nazwie pliku $module jest załadowany
	 *
	 * @param string $module
	 * @return bool
	 */
	public function is_loaded($module) {
		return key_exists($module, $this->func);
	}
	public function getModulesData() {
		return $this->modulesinfo;
	}
}

class bot_events extends bot_functions {
	/**
	 * Funkcja ktora smartirc wywoluje co 1000 milisekund
	 *
	 */
	public function ontimer(&$irc) {
		$this->time+=1000;
		if ($this->time%10000==0) {
		//	echo time()."\n";
			if (file_put_contents(BOT_LOCK_FILE, time(), LOCK_EX)) {
				$this->debug('Updated lock file', DBG_INFO, 3);
			} else $this->debug('Couldn\'t update lock file!');
		}
		if ($this->time%10000==0) {
			if (count($this->irc->channel)==0 && $this->autojoin) {
				$this->debug('Joining default channel.', DBG_WARN, 2);
				$this->irc->join(CHANNEL);
			}
		}
		unset($this->justunloaded);
		foreach ($this->ontimer as $k=>$v) {
			if ($k == 0 || $this->time%$k==0) {
				$this->debug('Running on timer event: module '.$v, DBG_INFO, 4);
				$this->exec($v);
			}
		}
	}
	/**
	 * Funkcja wykonywana gdy ktoś dołączy do kanału
	 *
	 */
	public function onjoin(&$irc, &$data) {
		foreach ($this->onjoin as $v) {
			$this->debug('Running on join event: module '.$v, DBG_INFO, 2);
			$this->exec($v, $data);		
		}
	}
	public function onleave(&$irc, &$data) {
		foreach ($this->onleave as $v) {
			$this->debug('Running on leave event: module '.$v, DBG_INFO, 2);
			$this->exec($v, $data);		
		}
	}
	public function ontopic(&$irc, &$data) {
		foreach ($this->ontopic as $v) {
			$this->debug('Running on topic event: module '.$v, DBG_INFO, 2);
			$this->exec($v, $data);		
		}
	}	
	public function onnick(&$irc, &$data) {
		foreach ($this->onnick as $v) {
			$this->debug('Running on nick event: module '.$v, DBG_INFO, 2);
			$this->exec($v, $data);
		}
	}
	public function onall(&$irc, &$data) {
		foreach ($this->onall as $v) {
			$this->debug('Running on all event: module '.$v, DBG_INFO, 4);
			$this->exec($v, $data);		
		}
	}
	public function onquery(&$irc, &$data) {
		$this->main($data, 'query');
		foreach ($this->onquery as $v) {
			$this->debug('Running on query event: module '.$v, DBG_INFO, 3);
			$this->exec($v, $data, 'query');		
		}
	}
	public function onchannelmessage(&$irc, &$data) {
		$this->main($data, 'msg');
		foreach ($this->onchannelmsg as $v) {
			$this->debug('Running on channel message event: module '.$v, DBG_INFO, 3);
			$this->exec($v, $data, 'msg');
		}
	}

}

class bot extends bot_events {
	/**
	 * Klasa bota
	 *
	 * @param SMARTIRC $irc referencja na obiekt smartirc
	 */
	public function __construct(&$irc, $safe=false) {
		$this->irc = &$irc;
		$this->data_temp = new Net_SmartIRC_data();
		$this->data_temp->nick = 'statup process';
		$this->setDebug(BOT_DEBUG);
		unset($this->data_temp);
		
		$this->safe = $safe;
		
		$this->reload_lang(); //jezyk
		$this->force_reload();//moduly
		$this->reload_ops(); //operatorzy
		
		//zeby dalo sie potem przeladowac moduly tak jak przy autostarcie
		$this->safe = false;
	}
	
	public function check_update($module_name) {
		if ($module_name === 'bot_core') {
			$co = @file_get_contents('http://update.tempaq2.blacksoft.eu/check.php?m=bot_core&v='.BOTVER);
			if ($co === '1')
				return true;					
			if ($co === '0')
				return false;
			
			return null;
		}
		if (isset($this->modulesinfo[$module_name])) {
			$m = $this->modulesinfo[$module_name];
			if (isset($m['update']) && isset($m['version'])) {
				if ($this->isUrl(trim($m['update']))) {
					$f =  ((substr_count($m['update'], '?'))?'&':'?');
					$url = $m['update'].$f.'m='.$module_name.'&v='.$m['version'];
					$co = @file_get_contents($url);
					if ($co === '1')
						return true;					
					if ($co === '0')
						return false;
					$this->debug($co);
					return null;
				}
				$this->debug($m['update'].' is not valid url address', DBG_WARN);
				return null;
			}
			return null;
		}
		$this->debug('Very nasty error. Module not found.', DBG_WARN, 1);
		return null;
	}
	
	public function download_module($module) {
		if (isset($this->modulesinfo[$module])) {
			$m = $this->modulesinfo[$module];
			if ($this->check_update($module) === false) {
				$f =  ((substr_count($m['update'], '?'))?'&':'?');
				$url = $m['update'].$f.'m='.$module.'&a=d';
				//@todo: dociaganie jezyka!
				$file = @file_get_contents($url);
				return $file;
			} else {
				$this->debug('Module '.$module.' doesn\'t need an update.', DBG_WARN, 2);
				return false;
			}
		}
		return false;
	}
	/**
	 * Przeładowywuje język
	 *
	 */
	public function reload_lang($lang = LANG) {
		unset($this->lang);
		$lang = new lang(new info(), $lang);
		foreach ($this->func as $k=>$v) {
			$lang->load_module($k, substr($this->modulesinfo[$k]['filename'], strrpos($this->modulesinfo[$k]['filename'], DIRECTORY_SEPARATOR)+1));
		}
		$this->lang = $lang;
		$this->debug('Lang reloaded', DBG_INFO, 2);
	}
	/**
	 * Przeładowywuje liste operatorow(adminow)
	 *
	 */
	public function reload_ops() {
		$res = sqlite::query('SELECT * FROM ops');
		$res = sqlite::fetch_all($res);
		$this->ops = $res;
		
		/*
		$table = new table('ops');
			$this->ops = $table->get();
		unset($table);*/
		$this->debug('Ops reloaded', DBG_INFO, 2);
	}
	public function memo($name, $val=null) {
		$b = &$this->module_memory[$this->exec_module];
		if ($val === null) {
			if (isset($b) && isset($b[$name]))
				return $b[$name];
		} else {
			if (!isset($b))
				$b = array();
			$b[$name] = $val;
			$this->module_memory[$this->exec_module] = $b;
			return $val;			
		}
		$this->debug('Property '.$name.' not found!', DBG_WARN, 2);
		return null;
	}
	/**
	 * Wysyła wiadomość o indeksie $msg
	 *
	 * @param string $msg
	 * @param mixed $rep
	 */
	public function send_text($msg, $rep=0, &$data=null) {
		$this->send($this->lang->text($msg, $rep), $data);		
	}
	public function sendarray($array, &$data=null) {
		if (is_array($array)) {
			$k=0;
			foreach ($array as $v) {
				//TODO: nie wiem czy nie bedzie spamowal teraz
				//wywalone bo spowalnialo tylko poczatek
				//if ($k>2 && $k%2 == 1) sleep(round($k*0.2, 0)); //co dwie wysylki odczekaj 1s (i niech to rosnie z czasem)
				//$k++;
				$this->send($v, $data);
			}
		}
	}
	/**
	 * Wysyła wiadomośc tam skąd przyszła:)
	 *
	 * @param string $msg Wiadomość
	 * @param SMARTIRC_data $data opcjonalnie referencja na date
	 */
	public function send($msg, &$data=null) {
		if ($data==null && $this->data_temp == null) return;
		elseif ($data==null) $data = $this->data_temp;
		if (is_object($data)) 
			if($data->type==2) {
				$this->debug('Sending msg('.strlen($msg).'): '.substr($msg,0, 20), DBG_INFO, 3);
				$this->sendmessage($msg, $data->channel);
			} elseif($data->type==4) {
				$this->debug('Sending priv msg('.strlen($msg).'): '.substr($msg,0, 20), DBG_INFO, 3);
				$this->sendpriv($msg, $data->nick);
			}
	}
	/**
	 * Wysyła wiadomość na kanał
	 *
	 * @param string $msg Tresc wiadomosci
	 * @param string $channel Nazwa kanału
	 */
	public function sendmessage($msg, $channel=CHANNEL) {
		$this->irc->message(SMARTIRC_TYPE_CHANNEL, $channel, $msg);
	}
	/**
	 * Wysyła prywatna wiadomosc
	 *
	 * @param string $msg wiadomosc
	 * @param string $who adresat
	 */
	public function sendpriv($msg, $who) {
		$this->irc->message(SMARTIRC_TYPE_QUERY, $who, $msg);
	}
	public function gettopic($channel) {
		$this->debug('Getting topic', DBG_INFO, 2);
		if (isset($this->irc->channel[$channel]))
			return $this->irc->channel[$channel]->topic;
		return false;
	}

	/**
	 * Funckja zajmująca się obsługą podstawowej funkcjonalnosci
	 *
	 * @param SMARTIRC_data $data
	 */
	public function main(&$data) {
		//komendy dla adminow
		$this->data_temp = $data;
		if ($this->is_admin($data->nick)) {
			switch ($data->messageex[0]) {
				case '!exit':
				case '!stfu':
				case '!zamknij':
					//pozegnaj sie:)
					if (!isset($data->messageex[1])||$data->messageex[1]==$this->irc->_nick) {
						$this->sendmessage($this->lang->text('byebye'), $data->channel);
						sleep(1);
						$this->debug('Quitting: '.$data->message, DBG_INFO, 1);
						$this->irc->quit(substr($data->message,strlen($data->messageex[0])+1));
						$this->irc->disconnect();
					}
					break;
				case '!restart':
					$this->debug('Restarting', DBG_WARN, 1);
					$this->irc->quit();
					$this->irc->disconnect();
					//exec("/usr/bin/php ./run.php");
					break;
				case '!load':
					if (isset($data->messageex[1])) {
						for ($i=1;$i<count($data->messageex); $i++) {
							if (!empty($data->messageex[$i]))
								if ($this->load_module((isset($this->modulesinfo[$data->messageex[$i]])?$this->modulesinfo[$data->messageex[$i]]['filename']:$data->messageex[$i]), $data))
									$this->send($this->lang->text('module_reloaded', $data->messageex[$i]), $data);
						}
					} else {
						$this->send($this->lang->text('wrong_syntax'), $data);
					}
					break;
		/*		case '!modules':
					$msg='';
					$this->debug('Sending modules list', DBG_INFO, 2);
					if (!isset($data->messageex[1]) || $data->messageex[1]=='loaded') {
						foreach ($this->func as $k=>$v) {
							$msg.=$k.', ';
						}
						$msg = $this->lang->text('loaded_modules').substr($msg, 0, strlen($msg)-2);
						$this->send($msg, $data);
					} else if ($data->messageex[1] == 'available') {
						$list = $this->load_modules($data, 1);
						foreach ($list as $k=>$v) {
							$msg.=$k.', ';
						}
						$msg = $this->lang->text('available_modules').substr($msg, 0, strlen($msg)-2);
						$this->send($msg, $data);
					}
					break; */
				case '!debug':
					$dane = $data->messageex[1];
					if (isset($dane)&&is_numeric($dane)) {
							$this->setDebug((int) $dane);
					}
					$this->send($this->lang->text('dbg_lvl', bot_base::set_debug()));
					break;
				case '!reload':
					if (isset($data->messageex[1])) {
						switch($data->messageex[1]) {
							case 'lang':
								if (isset($data->messageex[2])) {
									$this->reload_lang($data->messageex[2]);
								} else 
									$this->reload_lang();
								$this->send($this->lang->text('lang_reloaded'), $data);
								break;
							case 'ops':
								$this->reload_ops();
								$this->send($this->lang->text('ops_reloaded'), $data);
								break;
							case 'modules':
								if (isset($data->messageex[2])&&$data->messageex[2]=='force') {
									$this->force_reload();
								} else {
									$this->reload_active_modules($data);
								}
								$this->send($this->lang->text('modules_reloaded'), $data);
								break;
						}
					}
					break;
				case '!uptime':
					$this->send($this->mktime(), $data);
					break;
			}
		}
		//komendy dla ZU
		switch ($data->messageex[0]) {
			case '!help':
				if (isset($data->messageex[1])) {
					$msg = (isset($this->modulesinfo[$data->messageex[1]]) && $this->modulesinfo[$data->messageex[1]]['description']!=='NONE')?$this->modulesinfo[$data->messageex[1]]['description']:$this->lang->text('no_help', $data->messageex[1]);
					$this->send($msg, $data);
				} else {
					$help = array('!help', '!version');
					foreach ($this->help as $v) {
						$help[]=$v;
					}
					foreach($this->modulesinfo as $k => $v) {
						if (is_object($v['module'])) {
							$x = $v['module']->getHelp($this->is_admin($data->nick));
							foreach ($x as $z) {
								$help[]=$z;
							}
						}
					}
					sort($help);
					$msg = "";
					foreach ($help as $v) {
							$msg.= "$v ";
					}
					$msg = $this->lang->text('available_com').$msg;
					$this->send($msg, $data);
				}
				break;
			case '!version':
				if (isset($data->messageex[1]) && $this->is_admin($data->nick)) {
					$m = $data->messageex[1];
					if (isset($this->modulesinfo[$m]) && isset($this->modulesinfo[$m]['version'])) {
						$this->send($m.' - v. '.$this->modulesinfo[$m]['version']);
					}
				} else {
					$this->debug('Sending version', DBG_INFO, 2);
					$this->send(BOTNAME.' v.'.BOTVER.' by blacksoft.eu', $data);
				}
				break;
			case BOTNAME:
				if (!isset($data->messageex[1]))
					$this->send(BOTNAME.' - IRC Bot by blacksoft.eu', $data);
				break;
		}
	}

	/**
	 * Wywołuje funkcje $func
	 *
	 * @param string $func Nazwa funkcji
	 */
	public function exec($func, &$data=null) {
		//ladne nazwy zmiennych do wykorzystania w modułach
		//global $_table_cols;
		$bot = &$this;
		$lang = $this->lang;
		$irc = &$this->irc;
		$lang = &$this->lang;
		$lang->module($func);
		//zapisujemy ktory moduł jest wykonywany i tymczasową zmienną data
		$this->data_temp = $data;
		$this->exec_module = $func;
		
		$d = (isset($data->messageex))?$data->messageex:null;
		$message = (isset($data->message)?$data->message:null);
		$module = ((isset($this->modulesinfo[$func]['module']))?$this->modulesinfo[$func]['module']:null);
		$parsed_module = (($module !== null)?$module->data($data):array());
		if (isset($this->func[$func])) {
			 eval($this->func[$func]);
		} elseif (!in_array($func, $this->justunloaded))
			$this->debug("Próba wywołania funkcji $func, która nie jest zdefiniowana!\n", DBG_ERROR, 1);
		$lang->unmodule();
		if ($module !== null) $module->data(null);
		unset($this->data_temp);
		unset($this->exec_module);
	}
}

?>